package com.zyl.tvolatile.single;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
 * @author zhaoyl
 * @date 2024/5/20 16:52
 * @description 说明
 * 懒汉式单例
 */
public class LazyMan {

    private  static  boolean flag_fs =false;
    public LazyMan() {
        synchronized (LazyMan.class){
            if (flag_fs==false){
                flag_fs =true;
            }
            else {
                throw  new RuntimeException("请避免使用反射破坏异常");
            }
        }
    }
    //避免指令重排
    private volatile static LazyMan lazyMan;

    public  static  LazyMan getInstance(){
        //双重检测锁锁模式 DCL懒汉式
        if(lazyMan==null){
            //避免多线程并发下有问题:
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan = new LazyMan();//不是原子性操作
                    /**
                     * 可能发生指令重排，多线程存在问题
                     * 1.分配内存空间
                     * 2.执行构造方法，初始化对象
                     * 3.把这个对象指向这个空间
                     * */
                }
            }
        }
        return lazyMan ;
    }

    //反射
    public static void main(String[] args) throws Exception  {
        LazyMan instance = LazyMan.getInstance();//对象1
        System.out.println(instance);

        Field flag = LazyMan.class.getDeclaredField("flag_fs");
        flag.setAccessible(true);//破坏字段的私有性

        //得到默认的public构造函数;getDeclaredConstructors可以得到所有访问权限的构造函数；getConstructors只能得到public修饰的构造函数
        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(LazyMan.class);
        //你可以调用setAccessible(true)方法，这将允许你访问那些非公有的成员，包括私有的构造器。
        declaredConstructor.setAccessible(true);
        //绕过可见性检查创建新实例
        LazyMan instance2  = declaredConstructor.newInstance();//反射创建对象

        //反射破坏单例
        flag.set(instance2,flag);
        LazyMan instance3  = declaredConstructor.newInstance();

        System.out.println(instance2);
        System.out.println(instance3);
    }

}
